package tablegenerator;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import parser.TrecEvalParser;

import flanagan.analysis.Stat;


public class LatexTableGenerator {

	public static void main(String[] args) throws FileNotFoundException
	{
		String path = "u";
		String[] dfs={
				"rr","bordafuse","condorcet",
				"combmin","combmed","combmax",
				"combsum", "combmnz", "combanz",
				"expcombsum", "expcombanz", "expcombmnz"};
		String[] titleCombination = {"Title-I","Title-R","Title-M","Title-I-R","Title-I-M","Title-R-M","Title-I-R-M"};
		String[] vdCombination = {"I-VD","R-VD","M-VD","I-R-VD","I-M-VD","R-M-VD","I-R-M-VD"};
		String[] allCombination = {"Title-VD",
				"Title-I-VD",
				"Title-R-VD",
				"Title-M-VD",
				"Title-I-R-VD",
				"Title-I-M-VD",
				"Title-R-M-VD",
				"Title-I-R-M-VD"};
		//String[] bestMethods = {"M.eval","I-M.combsum.eval","Title-I-M.combsum.eval","I-M-VD.combsum.eval","Title-I-M-VD.combsum.eval"};
		String[] bestMethods = {"M.eval","I-M.combmnz.eval","Title-I-M.combmnz.eval","I-M-VD.combmnz.eval","Title-I-M-VD.combmnz.eval"};
		ArrayList<String> methods = new ArrayList<>();
		
		for (String method: bestMethods)
			methods.add(method);
	
		String[] measures = {"map","recip_rank","P_10","ndcg_cut_10"};


		
		Map<String,String> mSyb = new HashMap<String,String>();
		mSyb.put("better", "1");
		mSyb.put("worse", "");
		
		Map<String,String> imSyb = new HashMap<String,String>();
		imSyb.put("better", "2");
		imSyb.put("worse", "");
		
		Map<String,String> timSyb = new HashMap<String,String>();
		timSyb.put("better", "3");
		timSyb.put("worse", "");
		
		Map<String,String> imdSyb = new HashMap<String,String>();
		imdSyb.put("better", "4");
		imdSyb.put("worse", "");
		
		Map<String,String> timdSyb = new HashMap<String,String>();
		timdSyb.put("better", "5");
		timdSyb.put("worse", "");
		
		Map<String, Map<String,String>> baselineSymbols = new HashMap<>();
		baselineSymbols.put("M.eval", mSyb);
		baselineSymbols.put("I-M.combmnz.eval", imSyb);
		baselineSymbols.put("Title-I-M.combmnz.eval", timSyb);
		baselineSymbols.put("I-M-VD.combmnz.eval", imdSyb);
		baselineSymbols.put("Title-I-M-VD.combmnz.eval", timdSyb);
		
		String[] baselines = bestMethods;
		Map<String, String[]> baselinesConfig = new HashMap<>();
		
		for (String method : methods)
			baselinesConfig.put(method, baselines);
		
		
		
		
	
		
		
		/*String[] methods = {"vd.eval",
							"votes-all.eval",
				            "rr-all.eval",
				            "bordafuse-all.eval",
				            "combmin-all.eval",
				            "combmax-all.eval",
				            "condorcet-all.eval",
				            "combsum-all.eval",
				            "combmnz-all.eval",
				            "combanz-all.eval",
				            "combgnz-all.eval",
				            "expcombsum-all.eval",
				            "expcombanz-all.eval",
				            "expcombmnz-all.eval",
				            
				            "votes.eval",
				            "rr.eval",
				            "bordafuse.eval",
				            "combmin.eval",
				            "combmax.eval",
				            "condorcet.eval",
				            "combsum.eval",
				            "combmnz.eval",
				            "combanz.eval",
				            "combgnz.eval",
				            "expcombsum.eval",
				            "expcombanz.eval",
				            "expcombmnz.eval",
				            
				            
				            "votes-k.eval",
				            "rr-k.eval",
				            "bordafuse-k.eval",
				            "combmin-k.eval",
				            "condorcet-k.eval",
				            "combsum-k.eval",
				            "combmnz-k.eval",
				            "combanz-k.eval",
				            "combgnz-k.eval",
				            "expcombsum-k.eval",
				            "expcombanz-k.eval",
				            "expcombmnz-k.eval",
				            
				            
				          
				            "rr-pcs.eval",
				            "bordafuse-pcs.eval",
				            "condorcet-pcs.eval",
				            "combsum-pcs.eval",
				            "combmnz-pcs.eval",
				            "combanz-pcs.eval",
				            "combgnz-pcs.eval",
				            "expcombsum-pcs.eval",
				            "expcombanz-pcs.eval",
				            "expcombmnz-pcs.eval"
				     				            };
				     				            */
		/*String[] methods = {"vd.eval","votes.eval","combmax.eval","rr.eval","bordafuse.eval","combgnz-pcs.eval",
				
				"combsum-pcs.eval","combanz-pcs.eval","combmnz-pcs.eval",
							"expcombsum-pcs.eval","expcombanz-pcs.eval","expcombmnz-pcs.eval",
							};

		String[] measures = {"map","recip_rank","P_10","ndcg_cut_10"};


		
		Map<String,String> lSyb = new HashMap<String,String>();
		lSyb.put("better", "l");
		lSyb.put("worse", "");
		
		
		Map<String,String> vSyb = new HashMap<String,String>();
		vSyb.put("better", "v");
		vSyb.put("worse", "");
		
		Map<String,String> rSyb = new HashMap<String,String>();
		rSyb.put("better", "r");
		rSyb.put("worse", "");
		
		Map<String,String> bSyb = new HashMap<String,String>();
		bSyb.put("better", "b");
		bSyb.put("worse", "");

		
		Map<String,String> sSyb = new HashMap<String,String>();
		sSyb.put("better", "s");
		sSyb.put("worse", "");
		
		Map<String,String> aSyb = new HashMap<String,String>();
		aSyb.put("better", "a");
		aSyb.put("worse", "");
		
		Map<String,String> mSyb = new HashMap<String,String>();
		mSyb.put("better", "m");
		mSyb.put("worse", "");
		
		Map<String,String> gSyb = new HashMap<String,String>();
		gSyb.put("better", "g");
		gSyb.put("worse", "");
		
		Map<String,String> SSyb = new HashMap<String,String>();
		SSyb.put("better", "S");
		SSyb.put("worse", "");
		
		Map<String,String> ASyb = new HashMap<String,String>();
		ASyb.put("better", "A");
		ASyb.put("worse", "");
		
			
		Map<String,String> MSyb = new HashMap<String,String>();
		MSyb.put("better", "M");
		MSyb.put("worse", "");
		
		Map<String,String> xSyb = new HashMap<String,String>();
		xSyb.put("better", "X");
		xSyb.put("worse", "");
		
		
		Map<String, Map<String,String>> baselineSymbols = new HashMap<>();
		baselineSymbols.put("vd.eval", lSyb);
		baselineSymbols.put("votes.eval", vSyb);
		baselineSymbols.put("rr.eval", rSyb);
		baselineSymbols.put("bordafuse.eval", bSyb);
		baselineSymbols.put("combsum-pcs.eval", sSyb);
		baselineSymbols.put("combanz-pcs.eval", aSyb);
		baselineSymbols.put("combmnz-pcs.eval", mSyb);
		baselineSymbols.put("combgnz-pcs.eval", gSyb);
		baselineSymbols.put("expcombsum-pcs.eval", SSyb);
		baselineSymbols.put("expcombanz-pcs.eval", ASyb);
		baselineSymbols.put("expcombmnz-pcs.eval", MSyb);
		baselineSymbols.put("combmax.eval", xSyb);

		Map<String, String[]> baselinesConfig = new HashMap<>();
		baselinesConfig.put("vd.eval","vd.eval,vd.eval".split(","));
		baselinesConfig.put("votes.eval",methods);
		baselinesConfig.put("combmax.eval", methods);
		baselinesConfig.put("rr.eval", methods);
		baselinesConfig.put("bordafuse.eval",methods);
		baselinesConfig.put("combsum-pcs.eval", methods);
		baselinesConfig.put("combanz-pcs.eval", methods);
		baselinesConfig.put("combmnz-pcs.eval",methods);
		baselinesConfig.put("combgnz-pcs.eval", methods);
		baselinesConfig.put("expcombanz-pcs.eval", methods);
		baselinesConfig.put("expcombmnz-pcs.eval", methods);
		baselinesConfig.put("expcombsum-pcs.eval", methods);
		
		*/
		/*
		 * 
		 * 
		
		Map<String,String> vdSyb = new HashMap<String,String>();
		vdSyb.put("better", "\\triangle");
		vdSyb.put("worse", "\\triangledown");
		
		Map<String,String> voteSyb = new HashMap<String,String>();
		voteSyb.put("better", "\\blacktriangle");
		voteSyb.put("worse", "\\blacktriangledown");

		baselineSymbols.put("votes-all.eval", voteSyb);
		baselineSymbols.put("rr-all.eval", voteSyb);
		baselineSymbols.put("bordafuse-all.eval", voteSyb);
		baselineSymbols.put("combmin-all.eval", voteSyb);
		baselineSymbols.put("combmax-all.eval", voteSyb);
		baselineSymbols.put("condorcet-all.eval", voteSyb);
		baselineSymbols.put("combsum-all.eval", voteSyb);
		baselineSymbols.put("combanz-all.eval", voteSyb);
		baselineSymbols.put("combmnz-all.eval", voteSyb);
		baselineSymbols.put("combgnz-all.eval", voteSyb);
		baselineSymbols.put("expcombanz-all.eval", voteSyb);
		baselineSymbols.put("expcombmnz-all.eval", voteSyb);
		baselineSymbols.put("expcombsum-all.eval", voteSyb);
		
		baselineSymbols.put("votes.eval", voteSyb);
		baselineSymbols.put("rr.eval", voteSyb);
		baselineSymbols.put("bordafuse.eval", voteSyb);
		baselineSymbols.put("combmin.eval", voteSyb);
		baselineSymbols.put("combmax.eval", voteSyb);
		baselineSymbols.put("condorcet.eval", voteSyb);
		baselineSymbols.put("combsum.eval", voteSyb);
		baselineSymbols.put("combanz.eval", voteSyb);
		baselineSymbols.put("combmnz.eval", voteSyb);
		baselineSymbols.put("combgnz.eval", voteSyb);
		baselineSymbols.put("expcombanz.eval", voteSyb);
		baselineSymbols.put("expcombmnz.eval", voteSyb);
		baselineSymbols.put("expcombsum.eval", voteSyb);
		
		
		baselineSymbols.put("votes-k.eval", voteSyb);
		baselineSymbols.put("rr-k.eval", voteSyb);
		baselineSymbols.put("bordafuse-k.eval", voteSyb);
		baselineSymbols.put("combmin-k.eval", voteSyb);
		baselineSymbols.put("condorcet-k.eval", voteSyb);
		baselineSymbols.put("combsum-k.eval", voteSyb);
		baselineSymbols.put("combanz-k.eval", voteSyb);
		baselineSymbols.put("combmnz-k.eval", voteSyb);
		baselineSymbols.put("combgnz-k.eval", voteSyb);
		baselineSymbols.put("expcombanz-k.eval", voteSyb);
		baselineSymbols.put("expcombmnz-k.eval", voteSyb);
		baselineSymbols.put("expcombsum-k.eval", voteSyb);
		
		*/
		
		
		/*
		baselinesConfig.put("vd.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("votes-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("rr-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("bordafuse-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("combmin-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("combmax-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("condorcet-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("combsum-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("combanz-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("combmnz-all.eval","vd.eval,vd.eval".split(","));
		baselinesConfig.put("combgnz-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("expcombanz-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("expcombmnz-all.eval", "vd.eval,vd.eval".split(","));
		baselinesConfig.put("expcombsum-all.eval", "vd.eval,vd.eval".split(","));
		
		
		
		baselinesConfig.put("votes.eval", "vd.eval,votes-all.eval".split(","));
		baselinesConfig.put("rr.eval", "vd.eval,rr-all.eval".split(","));
		baselinesConfig.put("bordafuse.eval", "vd.eval,bordafuse-all.eval".split(","));
		baselinesConfig.put("combmin.eval", "vd.eval,combmin-all.eval".split(","));
		baselinesConfig.put("combmax.eval", "vd.eval,combmax-all.eval".split(","));
		baselinesConfig.put("condorcet.eval", "vd.eval,condorcet-all.eval".split(","));
		baselinesConfig.put("combsum.eval", "vd.eval,combsum-all.eval".split(","));
		baselinesConfig.put("combanz.eval", "vd.eval,combanz-all.eval".split(","));
		baselinesConfig.put("combmnz.eval","vd.eval,combmnz-all.eval".split(","));
		baselinesConfig.put("combgnz.eval", "vd.eval,combgnz-all.eval".split(","));
		baselinesConfig.put("expcombanz.eval", "vd.eval,expcombanz-all.eval".split(","));
		baselinesConfig.put("expcombmnz.eval", "vd.eval,expcombmnz-all.eval".split(","));
		baselinesConfig.put("expcombsum.eval", "vd.eval,expcombsum-all.eval".split(","));
		
		
		baselinesConfig.put("votes-k.eval", "vd.eval,votes.eval".split(","));
		baselinesConfig.put("rr-k.eval", "vd.eval,rr.eval".split(","));
		baselinesConfig.put("bordafuse-k.eval", "vd.eval,bordafuse.eval".split(","));
		baselinesConfig.put("combmin-k.eval", "vd.eval,combmin.eval".split(","));
		baselinesConfig.put("combmax-k.eval", "vd.eval,combmax.eval".split(","));
		baselinesConfig.put("condorcet-k.eval", "vd.eval,condorcet.eval".split(","));
		baselinesConfig.put("combsum-k.eval", "vd.eval,combsum.eval".split(","));
		baselinesConfig.put("combanz-k.eval", "vd.eval,combanz.eval".split(","));
		baselinesConfig.put("combmnz-k.eval","vd.eval,combmnz.eval".split(","));
		baselinesConfig.put("combgnz-k.eval", "vd.eval,combgnz.eval".split(","));
		baselinesConfig.put("expcombanz-k.eval", "vd.eval,expcombanz.eval".split(","));
		baselinesConfig.put("expcombmnz-k.eval", "vd.eval,expcombmnz.eval".split(","));
		baselinesConfig.put("expcombsum-k.eval", "vd.eval,expcombsum.eval".split(","));
		
		
		baselinesConfig.put("rr-pcs.eval", "vd.eval,rr-k.eval".split(","));
		baselinesConfig.put("bordafuse-pcs.eval", "vd.eval,bordafuse-k.eval".split(","));
		baselinesConfig.put("condorcet-pcs.eval", "vd.eval,condorcet-k.eval".split(","));
		baselinesConfig.put("combsum-pcs.eval", "vd.eval,combsum-k.eval".split(","));
		baselinesConfig.put("combanz-pcs.eval", "vd.eval,combanz-k.eval".split(","));
		baselinesConfig.put("combmnz-pcs.eval","vd.eval,combmnz-k.eval".split(","));
		baselinesConfig.put("combgnz-pcs.eval", "vd.eval,combgnz-k.eval".split(","));
		baselinesConfig.put("expcombanz-pcs.eval", "vd.eval,expcombanz-k.eval".split(","));
		baselinesConfig.put("expcombmnz-pcs.eval", "vd.eval,expcombmnz-k.eval".split(","));
		baselinesConfig.put("expcombsum-pcs.eval", "vd.eval,expcombsum-k.eval".split(","));
		
		*/
		
		generateTable(path,methods.toArray(new String[1]), baselinesConfig, measures, baselineSymbols, 0.0500);
		

	}

	
	public static void generateTable(String pathToResult, String[] methods, Map<String,String[]> baselinesConfig, String[] measures, Map<String,Map<String,String>> baselineSymbols,double sigLevel) throws FileNotFoundException
	{
		for (String method : methods)
		{
			Map<String,Map<String,Double>> treatEval = TrecEvalParser.parseMethodEval(new File(pathToResult,method));
			Map<String,Map<String,Map<String,Double>>> baseEvals = new HashMap<>();
			String[] baselines =  baselinesConfig.get(method);
			
			for (String baseline: baselines){
				baseEvals.put(baseline, TrecEvalParser.parseMethodEval(new File(pathToResult,baseline)));
			}
				
			System.out.println(generateMethodRow(
					                            baselines,
					                            method,
					                            baseEvals,treatEval,
					                            measures,baselineSymbols,sigLevel
					                            )
					           );
		}
	}
	
	public static String generateMethodRow(String treatName, 
			Map<String,Map<String,Double>> baseEval,Map<String,Map<String,Double>> treatEval,
			String[] measures,
			Map<String,String> baselineSymbols,  
			double sigLevel)
	{
		StringBuilder rowString = new StringBuilder();
		rowString.append(treatName + " & ");

		Map<String,Double> treatAvgMeasures = treatEval.get("all");
		Map<String,Double> baseAvgMeasures = baseEval.get("all");

		for (int i = 0; i < measures.length; i++)
		{
			String separator = (i == measures.length-1)?"\\\\":" & ";

			double treatValue = treatAvgMeasures.get(measures[i]);
			double baseValue = baseAvgMeasures.get(measures[i]);

			String symbol = formatSignificanceSymbol(baseEval, treatEval, measures[i],baselineSymbols, sigLevel); 

			String measureCell = String.format(" %.4f$^{%s}$ %s ",treatValue,symbol,separator);

			rowString.append(measureCell);
		}
		return rowString.toString();	
	}


	private static String formatSignificanceSymbol(Map<String, Map<String, Double>> baseEval,
												   Map<String, Map<String, Double>> treatEval, 
												   String measure, Map<String, String> baselineSymbols, 
												   double sigLevel ) {
		
		double baseValue = baseEval.get("all").get(measure);
		double treatValue =treatEval.get("all").get(measure) ;
		
		if (isSig(baseEval, treatEval, measure,sigLevel) && Double.compare(treatValue, baseValue) > 0)
		{
			return baselineSymbols.get("better");
		} else if (isSig(treatEval,baseEval,measure, sigLevel) &&  Double.compare(treatValue, baseValue) < 0){
			return  baselineSymbols.get("worse");
		}
			
		return "";
	}


	private static String formatSignificanceSymbols(Map<String,Map<String, Map<String, Double>>> baseEvals,
			   Map<String, Map<String, Double>> treatEval, 
			   String measure, Map<String,Map<String, String>> baselineSymbolsMap, 
			   double sigLevel) {
		
		String symbol = "{";
		
		
		for (String base : baseEvals.keySet())
		{
			symbol += formatSignificanceSymbol(baseEvals.get(base), treatEval, measure, baselineSymbolsMap.get(base), sigLevel);
		}
		
		return symbol+"}";
		
	}
	
	
	public static String generateMethodRow(String[] baseNames, String treatName, 
			Map<String,Map<String,Map<String,Double>>> baseEvals,Map<String,Map<String,Double>> treatEval,
			String[] measures,
			Map<String,Map<String,String>> baselineSymbols,  
			double sigLevel)
	{
		StringBuilder rowString = new StringBuilder();
		rowString.append(treatName + " & ");



		for (int i = 0; i < measures.length; i++)
		{
			Map<String,Double> treatAvgMeasures = treatEval.get("all");
			double treatValue = treatAvgMeasures.get(measures[i]);
			String sigSymbols = "";
			for (String base: baseNames)
			{

				Map<String,Map<String,Double>> baseEval = baseEvals.get(base);
				Map<String,Double> baseAvgMeasures = baseEval.get("all");



				double baseValue = baseAvgMeasures.get(measures[i]);

				sigSymbols = formatSignificanceSymbols(baseEvals, treatEval, measures[i], baselineSymbols, sigLevel);
			}

			String separator = (i == measures.length-1)?"\\\\":" & ";
			rowString.append(String.format(" %.4f $^%s$ %s",treatValue,sigSymbols,separator ));
		}
		return rowString.toString();	
	}


	public static String generateMethodRow2(String[] baseNames, String treatName, 
			Map<String,Map<String,Map<String,Double>>> baseEvals,Map<String,Map<String,Double>> treatEval,
			String[] measures,
			Map<String,Map<String,String>> baselineSymbols,  
			double sigLevel)
	{
		StringBuilder rowString = new StringBuilder();
		rowString.append(treatName + " & ");



		for (int i = 0; i < measures.length; i++)
		{
			Map<String,Double> treatAvgMeasures = treatEval.get("all");
			double treatValue = treatAvgMeasures.get(measures[i]);
			String sigSymbols = "";
			for (String base: baseNames)
			{

				Map<String,Map<String,Double>> baseEval = baseEvals.get(base);
				Map<String,Double> baseAvgMeasures = baseEval.get("all");



				double baseValue = baseAvgMeasures.get(measures[i]);

				String symbol="";

				if (isSig(baseEval, treatEval, measures[i],sigLevel) && Double.compare(treatValue, baseValue) > 0)
				{
					symbol = baselineSymbols.get(base).get("better05");
				}  else if (isSig(treatEval, baseEval, measures[i],sigLevel) && Double.compare(treatValue, baseValue) < 0) {
					symbol = baselineSymbols.get(base).get("worse05");
				} 

				sigSymbols = String.format("%s%s",sigSymbols,symbol);
			}

			String separator = (i == measures.length-1)?"\\\\":" & ";
			rowString.append(String.format(" %.4f $^%s$ %s",treatValue,sigSymbols,separator ));
		}
		return rowString.toString();	
	}
	
	public static double diffMean(double baseSample[], double treatSample[])
	{
		double[] diff = new double[baseSample.length];

		for (int i = 0; i < diff.length; i++)
		{
			diff[i]= treatSample[i]-baseSample[i];
		}

		return Stat.mean(diff);
	}


	public static double diffStandardDiv(double baseSample[], double treatSample[])
	{
		double[] diff = new double[baseSample.length];

		for (int i = 0; i < diff.length; i++)
		{
			diff[i]= treatSample[i]-baseSample[i];
		}

		return Stat.standardDeviation(diff);
	}

	public static double pValue(double baseSample[], double treatSample[])
	{
		double t =  ( diffMean(baseSample, treatSample) / diffStandardDiv(baseSample, treatSample) ) * Math.sqrt((double)baseSample.length);

		return Stat.pValue(t, baseSample.length);
	}

	public static boolean isSig(Map<String,Map<String,Double>> base, Map<String,Map<String,Double>> treat,String measure, double sigLevel)
	{

		Map<String,Double> baseMap = new HashMap<>();
		Map<String,Double> treatMap = new HashMap<>();
		
		for (String qno : base.keySet())
		{
			if (qno.equalsIgnoreCase("all"))
				continue;
			baseMap.put(qno, base.get(qno).get(measure));
			treatMap.put(qno, treat.get(qno).get(measure));
		}

		try{
			
			 SetRetrievalComparator comparator = new SetRetrievalComparator(baseMap, treatMap);
			
			if (Double.compare(comparator.pairedTTest(),sigLevel) < 0 )
				return true;
		} catch (IllegalArgumentException e){
			return false;
		}
		return false;

	}

}
